/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pedigreereconstruction;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import relationships.Relationship;
import relationships.ProbabilisticRelationship;
import relationships.RelationshipTypes;


import javax.swing.JFrame;

import com.mxgraph.swing.mxGraphComponent;
import com.mxgraph.view.mxGraph;

/**
 *
 * @author arthiramachandran
 */
public class ProbabilisticPedigree extends Pedigree implements Comparable {

    double likelihood;
    double logLikelihoodOfNull;

    // create a deep copy?
    public ProbabilisticPedigree(ProbabilisticPedigree other) {
        for (Iterator<Relationship> r_iterator =
                other.getRelationshipIterator(); r_iterator.hasNext();) {
            ProbabilisticRelationship r =
                    (ProbabilisticRelationship) r_iterator.next();
            this.addRelationship(r, r.isRelationshipSymmetric());
        }
    }

    public ProbabilisticPedigree() {
        super();
    }

    public void computeLogProbability() {
        double prob = 0;
        for (Iterator<Relationship> r_iterator = this.getRelationshipIterator();
                r_iterator.hasNext();) {
            ProbabilisticRelationship r =
                    (ProbabilisticRelationship) r_iterator.next();
            if (r.containsMissing()) {
                continue;
            }
            try {
                // TODO: shouldnt need to do this here.
                if (Double.isInfinite(Math.log10(r.getRelationshipLikelihood()))) {
                    r.calculateRelationshipLikelihood();
                }
            } catch (Exception ex) {
                Logger.getLogger(ProbabilisticPedigree.class.getName()).log(
                        Level.SEVERE, null, ex);
            }
            prob = prob + Math.log10(r.getRelationshipLikelihood());
        }
        likelihood = prob;
        try {
            this.logLikelihoodOfNull = this.logLikelihoodOfNull();
        } catch (Exception ex) {
            Logger.getLogger(ProbabilisticPedigree.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    void setRelationshipProbability(String individual1, String individual2,
            double probability) {
    }

    void setPedigreeProbability(double l) {
        this.likelihood = l;
    }

    public void addRelationship(ProbabilisticRelationship r, boolean symmetric) {
        super.addRelationship(r, symmetric);
        this.likelihood = this.likelihood * r.getRelationshipLikelihood();
    }

    /*
    @Override
    public void addIndividual(Individual i) {
    throw new UnsupportedOperationException("Not supported yet.");
    }
    
    @Override
    public void addRelationship(Relationship r) {
    throw new UnsupportedOperationException("Not supported yet.");
    }
    
    @Override
    public void modifyExistingRelationship(Relationship old_r, Relationship new_r) {
    throw new UnsupportedOperationException("Not supported yet.");
    }
    
    @Override
    public Pedigree splitPedigree(Double percentageToKeep) {
    throw new UnsupportedOperationException("Not supported yet.");
    }
    
    public void calculatePedigreeLikelihood() {
    throw new UnsupportedOperationException("Not supported yet.");
    }
    
    @Override
    public Relationship getRelationship(Individual i1, Individual i2) {
    throw new UnsupportedOperationException("Not supported yet.");
    }
    
    @Override
    public Individual getParents(Individual i1) {
    throw new UnsupportedOperationException("Not supported yet.");
    }
    
    
    @Override
    public void drawPedigree() {
    throw new UnsupportedOperationException("Not supported yet.");
    }
    
    @Override
    public List<Individual> getPedigreeRoots() {
    throw new UnsupportedOperationException("Not supported yet.");
    }
     * 
     */
    // TODO: where is the best place to catch this exception?
    public double logModelLikelihoodOverNull() throws Exception {
        //System.out.println(this.likelihood + " " + this.logLikelihoodOfNull());
        //return (this.likelihood - this.logLikelihoodOfNull());
        return (this.likelihood - this.logLikelihoodOfNull);
    }

    public double logLikelihoodOfNull() throws Exception {
        double nullLogLikelihood = 0;
        for (Iterator<Relationship> r_iterator = this.getRelationshipIterator();
                r_iterator.hasNext();) {
            ProbabilisticRelationship r =
                    (ProbabilisticRelationship) r_iterator.next();
            if (r.containsMissing()) {
                continue;
            }

            /*
            ProbabilisticRelationship nullR = new ProbabilisticRelationship(
            r.individual1, r.individual2, r.totalSharedIBD,
            r.numberOfSharedSegments, PedigreeReconstruction.unrelated);
            nullR.setRelationshipDistribution(PedigreeReconstruction.knownPairwiseDistributions.get(PedigreeReconstruction.unrelated));
            nullR.calculateRelationshipLikelihood();
            if (nullR.getRelationshipLikelihood() > 1) {
            throw new Exception("Probabilities should not be > 1\n" + nullR);
            }
             * 
             */
            //ProbabilisticRelationship pr =
            //        (ProbabilisticRelationship) r_iterator.next();
            /*if (r.getRelationshipLikelihood() < nullR.getRelationshipLikelihood()) {
            System.out.println("real vs null (bad ) "
            + r.getRelationshipLikelihood() + " "
            + nullR.getRelationshipLikelihood() + " " + r + " " + nullR);
            } else {
            System.out.println("real vs null (good) "
            + r.getRelationshipLikelihood() + " "
            + nullR.getRelationshipLikelihood() + " " + r + " " + nullR);
            }
             * 
             */
            //nullLogLikelihood += Math.log10(nullR.getRelationshipLikelihood());
            double l = r.calculateNullLikelihood();
            nullLogLikelihood += Math.log10(l);
            if (!r.isRelationshipSymmetric()) // account for both sides of an unrelated relationship
            {
                nullLogLikelihood +=
                        Math.log10(l);
            }
        }
        if (nullLogLikelihood > 0) {
            throw new Exception(
                    "Probabilities should not be > 1; Likelihood = " + nullLogLikelihood);
        }
        return nullLogLikelihood;
    }

    boolean hasCommonRelationship(ProbabilisticPedigree p) {
        int numberOfCommonRelationships = 0;

        for (Iterator<Relationship> r_iterator = this.getRelationshipIterator(); r_iterator.hasNext();) {
            ProbabilisticRelationship r =
                    (ProbabilisticRelationship) r_iterator.next();
            /*if (r.individual1.id.equals("K6001") && r.individual2.id.equals("K5910")
            && r.relationshipTypeEquals("SIBLINGS")) {
            System.out.println(p.containsRelationship(r)
            + "\n" + this.printGraph() + "\n--\n" + p.printGraph() + "\n-----\n");
            }
            if (r.individual2.id.equals("K6001") && r.individual1.id.equals("K5910")
            && r.relationshipTypeEquals("SIBLINGS")) {
            System.out.println(p.containsRelationship(r)
            + "\n" + this.printGraph() + "\n--\n" + p.printGraph()+ "\n-----\n");
            
            }
             * 
             */
            if (p.containsRelationship(r)) {
                numberOfCommonRelationships++;
                //return true;
            }
            if (p.containsRelationshipWithMissingParent(r)) {
                //System.out.println(r + "---" + this.printGraph() + "--" + p.printGraph());
                //return true;
                numberOfCommonRelationships++;
            }
            if (this.getNumberOfIndividuals() <= 3 || p.getNumberOfIndividuals() <= 3) {
                if (numberOfCommonRelationships >= 1) {
                    return true;
                }
            }
            if (numberOfCommonRelationships >= 2) {
                return true;
            }
        }
        return false;
    }

    public Iterable<Relationship> getRelationships() {
        return super.getRelationships();
    }

    boolean isConsistent() throws Exception {
        // everyone has only < 2 parents

        for (Individual i : this.getIndividuals()) {
            ArrayList<Individual> parents = this.getParents(i);
            int num_parents = parents.size();
            /*
             * take it out of try-catch
             * switch to enum
             */
            /*
            for (Iterator<Relationship> r_iterator =
            this.getIncomingRelationships(i); r_iterator.hasNext();) {
            ProbabilisticRelationship r =
            (ProbabilisticRelationship) r_iterator.next();
            if (r.relationshipTypeEquals("PARENT_CHILD")) {
            num_parents++;
            //if(num_parents > 2){break;}
            }
            }
             * 
             */
            // TODO: add it in
            /*if (!i.isMissing() && num_parents != 2) {
            System.out.println(i + "--\n" + num_parents + " " + this.getIndividuals() + this.printGraph());
            return false;
            }
             * 
             */
            if (num_parents > 2) {
                System.out.println("Inconsistent: Individual " + i + " has "
                        + num_parents + " parents: " + parents);
                return false;
            }

            // TODO: list these out first
            ArrayList<Individual> grandparents = this.getGrandparents(i);
            if (grandparents.size() > 4) {
                System.out.println("Inconsistent: Individual " + i + " has "
                        + grandparents.size() + " grandparents");
                return false;
            }

            // parents cannot be siblings
            if (num_parents == 2) {
                // allowing for further out relationships though
                /*if (this.getParents(i).get(1) == null) {
                throw new Exception("Weird: " + i + " " + this.printGraph());
                }
                 * 
                 */
                Relationship r =
                        this.getRelationship(parents.get(0), parents.get(1));
                if (r != null && r.relationshipType.equals(PedigreeReconstruction.siblings)) {
                    System.out.println("Inconsistent: Siblings "
                            + parents.get(0) + " and "
                            + parents.get(1)
                            + "cannot be parents of the same individual " + i);
                    return false;
                }
            }

            // TODO: other checks
            /*
             * 1. siblings have same parents
             * 2. siblings have same grandparents
             * 3. siblings have same siblings
             */
            // TODO: still accounting for not all relationships being there. so these are subsets
            // TODO super inefficient now
            for (Individual s : this.getSiblings(i)) {
                // same parents
                ArrayList<Individual> parents_s = this.getParents(s);
                if (parents.size() > parents_s.size()) {
                    for (Individual parent : parents_s) {
                        if (!parents.contains(parent)) {
                            System.out.println("Inconsistent: siblings " + i
                                    + " and " + s + " don't have same parents");
                            return false;
                        }
                    }
                } else {
                    for (Individual parent : parents) {
                        if (!parents_s.contains(parent)) {
                            System.out.println("Inconsistent: siblings " + i
                                    + " and " + s + " don't have same parents");
                            return false;
                        }
                    }
                }
                // same grand parents
                ArrayList<Individual> grandparents_s = this.getGrandparents(s);
                if (grandparents.size() > grandparents_s.size()) {
                    for (Individual gp : grandparents_s) {
                        if (!grandparents.contains(gp)) {
                            System.out.println("Inconsistent: siblings " + i
                                    + " and " + s + " don't have same grandparents");
                            return false;
                        }
                    }
                } else {
                    for (Individual gp : grandparents) {
                        if (!grandparents_s.contains(gp)) {
                            System.out.println("Inconsistent: siblings " + i
                                    + " and " + s + " don't have same grandparents");
                            return false;
                        }
                    }
                }
                // same other siblings
                // same aunts/uncles
                ArrayList<Individual> avun = this.getAvuncular(i);
                ArrayList<Individual> avun_s = this.getAvuncular(s);
                if (avun.size() != avun_s.size()) {
                    System.out.println("Inconsistent: siblings " + i
                            + " and " + s + " have different number of aunts/uncles");
                    return false;
                }
                if (avun.size() > avun_s.size()) {
                    for (Individual gp : avun_s) {
                        if (!avun.contains(gp)) {
                            System.out.println("Inconsistent: siblings " + i
                                    + " and " + s + " don't have same aunts/uncles");
                            return false;
                        }
                    }
                } else {
                    for (Individual gp : avun) {
                        if (!avun_s.contains(gp)) {
                            System.out.println("Inconsistent: siblings " + i
                                    + " and " + s + " don't have same aunts/uncles");
                            System.out.println("For " + i + ": " + avun);
                            System.out.println("For " + s + ": " + avun_s);
                            return false;
                        }
                    }
                }

            }

        }

        // if they have the same parents; they should be siblings
        for (Individual i1 : this.getIndividuals()) {
            ArrayList<Individual> parents1 = this.getParents(i1);
            for (Individual i2 : this.getIndividuals()) {
                ArrayList<Individual> parents2 = this.getParents(i2);
                boolean sibs = true;
                if (parents2.isEmpty()) {
                    sibs = false;
                }
                for (Individual parent2 : parents2) {
                    boolean match = false;
                    for (Individual parent1 : parents1) {
                        if (parent1.missingEquals(parent2)) {
                            match = true;
                        }
                    }
                    if (!match) {
                        sibs = false;
                    }
                }
                if (sibs) {
                    //System.out.println("SIBS: " + parents1 + " " + this.getParents(i2));
                    Relationship r = this.getRelationship(i1, i2);
                    if (r == null) {
                        continue; // it's ok if sibling relationship isnt present?
                    } else if (!r.relationshipType.equals(PedigreeReconstruction.siblings)) {
                        //System.out.println("FALSE" + i1 + " " + i2 + "\n" + this.printGraph());
                        System.out.println("Inconsistent: " + i1 + " and " + i2
                                + " should be sibs but aren't");
                        return false;
                    }
                }
            }
        }

        // if not sibs, they shouldnt share parents (even missing parents)
        for (Iterator<Relationship> r_iterator =
                this.getRelationshipIterator(); r_iterator.hasNext();) {
            ProbabilisticRelationship r =
                    (ProbabilisticRelationship) r_iterator.next();
            if (!r.relationshipType.equals(PedigreeReconstruction.siblings)) {
                for (Individual p1 : this.getParents(r.individual1)) {
                    for (Individual p2 : this.getParents(r.individual2)) {
                        // shouldn't have same parents
                        if (p1.missingEquals(p2)) {
                            System.out.println("Inconsistent: " + r.individual1 + " and " + r.individual2
                                    + " shouldn't share parents but they do");

                            return false;
                        }
                    }
                }
            }
        }


        // child's child should be grandchild
        for (Individual i : this.getIndividuals()) {
            for (Iterator<Relationship> r_iterator =
                    this.getIncomingRelationships(i); r_iterator.hasNext();) {
                ProbabilisticRelationship r =
                        (ProbabilisticRelationship) r_iterator.next();

                if (r.relationshipType.equals(PedigreeReconstruction.parent_child)) {
                    Individual i2 = r.getOtherIndividual(i);
                    for (Iterator<Relationship> r2_iterator =
                            this.getIncomingRelationships(i2); r2_iterator.hasNext();) {
                        ProbabilisticRelationship r2 =
                                (ProbabilisticRelationship) r2_iterator.next();
                        if (r2.relationshipType.equals(PedigreeReconstruction.parent_child)) {
                            Individual i3 = r2.getOtherIndividual(i2);
                            ProbabilisticRelationship r3 =
                                    (ProbabilisticRelationship) this.getRelationship(i, i3);
                            if (r3 != null) {
                                if (!r2.relationshipType.equals(PedigreeReconstruction.grandparent_grandchild)) {
                                    System.out.println("Inconsistent: Child of " + i
                                            + " should be grandchild of " + i2);

                                    return false;
                                }
                            }

                        }
                    }
                }
            }

        }

        // siblings should be child's aunts/uncles
        for (ProbabilisticRelationship r : this.getAvuncularRelationships()) {
            // sibs of i1 should be parents of i2
            // need to check direction for the graph
            // both parents can't be missing
            int numNonMissingParents = 0;
            //System.out.println(r);
            for (Individual parent : this.getParents(r.individual2)) {
                //System.out.println(parent);
                if (parent.isMissing()) {
                    continue;
                }
                numNonMissingParents++;
                ProbabilisticRelationship r2 =
                        (ProbabilisticRelationship) this.getRelationship(parent, r.individual1);
                //System.out.println(r2);
                if (r2 != null) {
                    if (!r2.relationshipTypeEquals("SIBLINGS")) {
                        System.out.println("Parent " + parent + "isn't siblings with aunt/uncle in " + r2);
                        return false;
                    }
                } else { // should have a p-c relationship defined
                    System.out.println("No parent-child connection between aunt/uncle & niece/nephew");
                    return false;
                }
            }
            if (numNonMissingParents < 1) {
                System.out.println("No non-missing parents");
                return false;
            }
        }
        // if siblings - both parents; else only 1 parent - to differentiate between sibs nad halfsibs

        // if parent-child -> shouldn't share other relationships
        for (ProbabilisticRelationship r : this.getParentChildRelationships()) {
            for (Individual s1 : this.getSiblings(r.individual1)) {
                for (Individual s2 : this.getSiblings(r.individual2)) {
                    if (s1.equals(s2)) {
                        System.out.println("Parent-child " + r + " shouldn't share additional relationships");
                        System.out.println("Common sib: " + s1 + " " + s2);
                        return false;
                    }
                }
            }
            // if inverse relationship exists - something wrong
            if (this.getRelationship(r.individual2, r.individual1) != null) {
                System.out.println("Parent-child shouldn't share inverse relationships");
                return false;
            }
            //if (this.getSiblings(r.individual1).)
        }

        // if grandparent-grandchild -> should be a connecting parent
        for (ProbabilisticRelationship r : this.getGrandparentGrandchildRelationships()) {
            // sibs of i1 should be parents of i2
            // need to check direction for the graph

            // both parents can't be missing
            int numNonMissingParents = 0;
            for (Individual parent : this.getParents(r.individual2)) {
                if (parent.isMissing()) {
                    continue;
                }
                numNonMissingParents++;
                ProbabilisticRelationship r2 =
                        (ProbabilisticRelationship) this.getRelationship(r.individual1, parent);
                if (r2 != null) {
                    if (!r2.relationshipTypeEquals("PARENT_CHILD")) {
                        System.out.println("Parent isn't child of grandparent");
                        return false;
                    }
                } else { // should have a p-c relationship defined
                    System.out.println("No parent-child connection between grandparent & grandchild");
                    return false;
                }
            }
            if (numNonMissingParents < 1) {
                System.out.println("No non-missing parents");
                return false;
            }
        }
        return true;
    }

    private ArrayList<Individual> getSiblings(Individual i) {
        ArrayList<Individual> sibs = new ArrayList<Individual>();
        for (Iterator<Relationship> r_iterator = this.getRelationships(i); r_iterator.hasNext();) {
            ProbabilisticRelationship r =
                    (ProbabilisticRelationship) r_iterator.next();
            if (r.relationshipTypeEquals("SIBLINGS")) {
                if (r.individual1.equals(i)) {
                    sibs.add(r.individual2);
                } else {
                    sibs.add(r.individual1);
                }
            }

        }
        return sibs;
    }

    public ArrayList<Individual> getParents(Individual i) {
        ArrayList<Individual> parents = new ArrayList<Individual>();
        try {
            for (Iterator<Relationship> r_iterator =
                    this.getIncomingRelationships(i); r_iterator.hasNext();) {
                ProbabilisticRelationship r =
                        (ProbabilisticRelationship) r_iterator.next();
                // TODO: might be wrong; might just need ot add one fo them
                if (r.relationshipType.equals(PedigreeReconstruction.parent_child)) {
                    //if (r.individual1.equals(i)) {
                    //    parents.add(r.individual2);
                    //} else {
                    parents.add(r.individual1);
                    //}
                }

            }
        } catch (Exception ex) {
            Logger.getLogger(ProbabilisticPedigree.class.getName()).log(Level.SEVERE, null, ex);
        }
        return parents;
    }

    public ArrayList<Individual> getChildren(Individual i) {
        ArrayList<Individual> children = new ArrayList<Individual>();
        //if (this.getRelationships(i) != null) {
        for (Iterator<Relationship> r_iterator =
                this.getOutgoingRelationships(i); r_iterator.hasNext();) {
            ProbabilisticRelationship r =
                    (ProbabilisticRelationship) r_iterator.next();
            if (r.relationshipTypeEquals("PARENT_CHILD")) {
                children.add(r.individual2);
            }
        }
        //}
        return children;
    }

    private ArrayList<Individual> getGrandparents(Individual i) {

        ArrayList<Individual> grandparents = new ArrayList<Individual>();
        try {
            for (Iterator<Relationship> r_iterator =
                    this.getIncomingRelationships(i); r_iterator.hasNext();) {
                ProbabilisticRelationship r =
                        (ProbabilisticRelationship) r_iterator.next();
                if (r.relationshipTypeEquals("GRANDPARENT_GRANDCHILD")) {
                    //if (r.individual1.equals(i)) {
                    //grandparents.add(r.individual2);
                    //} else {
                    grandparents.add(r.individual1);
                    //}
                }

            }
        } catch (Exception ex) {
            Logger.getLogger(ProbabilisticPedigree.class.getName()).log(Level.SEVERE, null, ex);
        }
        /*
        if (!grandparents.isEmpty()) {
        System.out.println("Grandparents:");
        System.out.println(this.printGraph());
        System.out.println(i + " " + grandparents);
        }
         * 
         */
        return grandparents;
    }

    // seems to be working... but still not enough parent-child within the pedigree
    void combineMissing() {
        //System.out.println("Earlier: " + this.printGraph());
        for (Individual m1 : this.getMissingIndividuals()) {
            for (Individual m2 : this.getMissingIndividuals()) {
                boolean equivalent = true;
                if (m1.missingEquals(m2)) {
                    continue;
                }
                if (this.getChildren(m1).size() != this.getChildren(m2).size()) {
                    equivalent = false;
                }
                // if m1's children and m2's children are siblings
                //System.out.println(m1 + " " + m2);               
                //System.out.println(m1 + " " + m2 + " " + this.getChildren(m1) + " " + this.getChildren(m2));
                for (Individual c1 : this.getChildren(m1)) {
                    for (Individual c2 : this.getChildren(m1)) {
                        ProbabilisticRelationship r =
                                (ProbabilisticRelationship) this.getRelationship(c1, c2);
                        if (r != null && !r.relationshipTypeEquals("SIBLINGS")) {
                            equivalent = false;
                        }
                    }
                }
                if (equivalent) {
                    //System.out.println(m1 + " " + m2);
                    this.replaceIndividual(m1, m2);
                }
            }
        }
        //System.out.println("Later" + this.printGraph());

    }

    public void replaceIndividual(Individual to, Individual from) {
        if (!this.containsIndividual(from)) {
            return;
        }
        if (this.getRelationships(from) == null && from.isMissing()) {
            this.removeIndividual(from);
            return;
        }
        //System.out.println(from + "\t" + this.getRelationships(from));
        for (Iterator<Relationship> r_iterator = this.getRelationships(from); r_iterator.hasNext();) {
            ProbabilisticRelationship r =
                    (ProbabilisticRelationship) r_iterator.next();
            ProbabilisticRelationship newR = null;
            if (r.individual1.missingEquals(from)) {
                newR =
                        new ProbabilisticRelationship(to, r.getOtherIndividual(from),
                        r.totalSharedIBD, r.numberOfSharedSegments, r.relationshipType);
            } else {
                newR =
                        new ProbabilisticRelationship(r.getOtherIndividual(from), to,
                        r.totalSharedIBD, r.numberOfSharedSegments, r.relationshipType);
            }
            newR.setRelationshipDistribution(r.getRelationshipDistribution());
            this.removeRelationship(r);
            this.addRelationship(newR, newR.isRelationshipSymmetric());
        }
    }

    private ArrayList<ProbabilisticRelationship> getAvuncularRelationships() {
        ArrayList<ProbabilisticRelationship> avuncular =
                new ArrayList<ProbabilisticRelationship>();
        for (Iterator<Relationship> r_iterator = this.getRelationshipIterator(); r_iterator.hasNext();) {
            ProbabilisticRelationship r =
                    (ProbabilisticRelationship) r_iterator.next();
            if (r.relationshipTypeEquals("AVUNCULAR")) {
                avuncular.add(r);
            }

        }
        return avuncular;
    }

    private ArrayList<ProbabilisticRelationship> getParentChildRelationships() {
        ArrayList<ProbabilisticRelationship> pc =
                new ArrayList<ProbabilisticRelationship>();
        for (Iterator<Relationship> r_iterator = this.getRelationshipIterator(); r_iterator.hasNext();) {
            ProbabilisticRelationship r =
                    (ProbabilisticRelationship) r_iterator.next();
            if (r.relationshipTypeEquals("PARENT_CHILD")) {
                pc.add(r);
            }

        }
        return pc;
    }

    private ArrayList<ProbabilisticRelationship> getGrandparentGrandchildRelationships() {
        ArrayList<ProbabilisticRelationship> gpgc =
                new ArrayList<ProbabilisticRelationship>();
        for (Iterator<Relationship> r_iterator = this.getRelationshipIterator(); r_iterator.hasNext();) {
            ProbabilisticRelationship r =
                    (ProbabilisticRelationship) r_iterator.next();
            if (r.relationshipTypeEquals("GRANDPARENT_GRANDCHILD")) {
                gpgc.add(r);
            }

        }
        return gpgc;
    }

    private ArrayList<Individual> getAvuncular(Individual i) {
        ArrayList<Individual> avuncular = new ArrayList<Individual>();
        try {
            for (Iterator<Relationship> r_iterator =
                    this.getIncomingRelationships(i); r_iterator.hasNext();) {
                ProbabilisticRelationship r =
                        (ProbabilisticRelationship) r_iterator.next();
                if (r.relationshipTypeEquals("AVUNCULAR")) {
                    //if (r.individual1.equals(i)) {
                    //    avuncular.add(r.individual2);
                    //} else {
                    avuncular.add(r.individual1);
                    //}
                }

            }
        } catch (Exception ex) {
            Logger.getLogger(ProbabilisticPedigree.class.getName()).log(Level.SEVERE, null, ex);
        }
        return avuncular;
    }

    /*
    @Override
    private Iterable<Individual> getFounders() {
    ArrayList<Individual> founders = new ArrayList<Individual>();
    for (Individual i : this.getIndividuals()) {
    if (this.getParents(i).isEmpty()) {
    founders.add(i);
    }
    }
    return founders;
    }
     * 
     */
    void drawPedigree() {
        // TODO: to implement

        // for each of the founders (those with no parents)
       /* for (Individual founder : this.getFounders())
        {
        
        }*
         * 
         */


        System.out.println(this.getFounders());
        // draw descendants from them
        // need to figure out how to do the crosses
        //throw new UnsupportedOperationException("Not yet implemented");
    }

    int addMissing(Individual i, int missingID) {
        Individual missing = new Individual("K" + missingID); // TODO: hard coded
        //System.out.println(missing);
        missingID--;

        ProbabilisticRelationship i1_m =
                new ProbabilisticRelationship(missing, i, -1, -1,
                -1, PedigreeReconstruction.parent_child);
        i1_m.setRelationshipDistribution(PedigreeReconstruction.knownPairwiseDistributions.get(PedigreeReconstruction.parent_child));
        this.addRelationship(i1_m, false);
        try {
            i1_m.calculateRelationshipLikelihood();
        } catch (Exception ex) {
            Logger.getLogger(ProbabilisticPedigree.class.getName()).log(Level.SEVERE, null, ex);
        }
        return missingID;
    }

    @Override
    public int compareTo(Object t) {
        ProbabilisticPedigree p = (ProbabilisticPedigree) t;
        int diff = 0;
        try {
            diff = (int) (-this.logModelLikelihoodOverNull() * 10e6
                    + p.logModelLikelihoodOverNull() * 10e6);
        } catch (Exception ex) {
            Logger.getLogger(ProbabilisticPedigree.class.getName()).log(Level.SEVERE, null, ex);
        }
        return diff;
    }

    int getNumberOfCommonRelationships(ProbabilisticPedigree p2) {
        int numberOfCommonRelationships = 1; // TODO: fix bug
        for (Iterator<Relationship> r2_iterator =
                p2.getRelationshipIterator(); r2_iterator.hasNext();) {
            ProbabilisticRelationship r2 =
                    (ProbabilisticRelationship) r2_iterator.next();
            if (this.containsRelationship(r2)) {
                numberOfCommonRelationships++;
            }
        }
        return numberOfCommonRelationships;
    }
}
